package com.efeichong.common.config;

import com.efeichong.common.domain.ResponseData;
import com.efeichong.common.exception.CustomException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.NonTransientDataAccessException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.HttpMediaTypeException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolationException;
import java.sql.SQLIntegrityConstraintViolationException;

@Slf4j
@RestControllerAdvice
public class ErrorControllerAdvice {

    @ExceptionHandler(CustomException.class)
    @CrossOrigin(allowedHeaders = "*", origins = "*", allowCredentials = "false", exposedHeaders = {"Cache-Control", "Content-Language", "Content-Type",
            "Expires", "X-Total-Count", "X-Total-Sum", "X-Total-Active"}, methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.OPTIONS})
    public ResponseData exception(CustomException e) {
        log.warn("CustomException:{}", e);
        return new ResponseData(e.getCode(), e.getMessage());
    }

    @ExceptionHandler(DuplicateKeyException.class)
    @CrossOrigin(allowedHeaders = "*", origins = "*", allowCredentials = "false", exposedHeaders = {"Cache-Control", "Content-Language", "Content-Type",
            "Expires", "X-Total-Count", "X-Total-Sum", "X-Total-Active"}, methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.OPTIONS})
    public ResponseData exception(DuplicateKeyException e) {
        log.error("DuplicateKeyException:{}", e);
        return new ResponseData(0, "该数据已存在，请勿重复提交数据!");
    }

    @ExceptionHandler({NonTransientDataAccessException.class})
    @CrossOrigin(allowedHeaders = "*", origins = "*", allowCredentials = "false", exposedHeaders = {"Cache-Control", "Content-Language", "Content-Type",
            "Expires", "X-Total-Count", "X-Total-Sum", "X-Total-Active"}, methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.OPTIONS})
    public ResponseData exception(NonTransientDataAccessException e) {
        Throwable rootCause = e.getRootCause();
        log.error("NonTransientDataAccessException:{}", e);
        if (rootCause instanceof SQLIntegrityConstraintViolationException) {
            SQLIntegrityConstraintViolationException sqlException = (SQLIntegrityConstraintViolationException) rootCause;
            if ("23000".equals(sqlException.getSQLState())) {
                if (sqlException.getErrorCode() == 1451) {
                    //外键约束
                    return new ResponseData(0, "存在关联数据，无法进行该操作");
                }
                if (sqlException.getErrorCode() == 1062) {
                    //唯一约束
                    return new ResponseData(0, "该数据已存在，请勿重复提交数据!");
                }
            }
        }
        return new ResponseData(0, e.getMessage());
    }

    @ExceptionHandler(HttpMediaTypeException.class)
    @CrossOrigin(allowedHeaders = "*", origins = "*", allowCredentials = "false", exposedHeaders = {"Cache-Control", "Content-Language", "Content-Type",
            "Expires", "X-Total-Count", "X-Total-Sum", "X-Total-Active"}, methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.OPTIONS})
    public ResponseData exception(HttpMediaTypeException e) {
        log.warn("请求数据类型不支持:", e);
        return new ResponseData(0, "http请求数据类型不支持!");
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    @CrossOrigin(allowedHeaders = "*", origins = "*", allowCredentials = "false", exposedHeaders = {"Cache-Control", "Content-Language", "Content-Type",
            "Expires", "X-Total-Count", "X-Total-Sum", "X-Total-Active"}, methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.OPTIONS})
    public ResponseData exception(HttpMessageNotReadableException e) {
        log.warn("请求数据报文格式存在问题:", e);
        return new ResponseData(0, "请求报文格式异常，请检查!");
    }

    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    @CrossOrigin(allowedHeaders = "*", origins = "*", allowCredentials = "false", exposedHeaders = {"Cache-Control", "Content-Language", "Content-Type",
            "Expires", "X-Total-Count", "X-Total-Sum", "X-Total-Active"}, methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.OPTIONS})
    public ResponseData exception(HttpRequestMethodNotSupportedException e) {
        log.warn("请求method类型不支持:", e);
        return new ResponseData(0, "http请求method类型不被支持!");
    }

    @ExceptionHandler(MissingServletRequestParameterException.class)
    @CrossOrigin(allowedHeaders = "*", origins = "*", allowCredentials = "false", exposedHeaders = {"Cache-Control", "Content-Language", "Content-Type",
            "Expires", "X-Total-Count", "X-Total-Sum", "X-Total-Active"}, methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.OPTIONS})
    public ResponseData exception(MissingServletRequestParameterException e) {
        log.warn("传入参数缺失:", e);
        return new ResponseData(0, "传入参数缺失," + e.getParameterName() + "为必传参数!");
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @CrossOrigin(allowedHeaders = "*", origins = "*", allowCredentials = "false", exposedHeaders = {"Cache-Control", "Content-Language", "Content-Type",
            "Expires", "X-Total-Count", "X-Total-Sum", "X-Total-Active"}, methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.OPTIONS})
    public ResponseData exception(MethodArgumentNotValidException e) {
        log.warn("传入数据校验不通过:", e);
        BindingResult result = e.getBindingResult();
        ResponseData rs = new ResponseData();
        if (result.hasErrors()) {
            rs = new ResponseData(0, result.getAllErrors().get(0).getDefaultMessage());
        } else {
            rs.setStatus(0);
            rs.setMessage("未知数据校验不通过错误,请确认数据格式是否正确!");
        }
        return rs;
    }

    @ExceptionHandler(ConstraintViolationException.class)
    @CrossOrigin(allowedHeaders = "*", origins = "*", allowCredentials = "false", exposedHeaders = {"Cache-Control", "Content-Language", "Content-Type",
            "Expires", "X-Total-Count", "X-Total-Sum", "X-Total-Active"}, methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.OPTIONS})
    public ResponseData exception(ConstraintViolationException e) {
        log.warn("传入数据校验不通过:", e);
        ResponseData rs = new ResponseData();
        rs.setStatus(0);
        rs.setMessage(e.getConstraintViolations().iterator().next().getMessage());
        return rs;
    }

    @ExceptionHandler(BindException.class)
    @CrossOrigin(allowedHeaders = "*", origins = "*", allowCredentials = "false", exposedHeaders = {"Cache-Control", "Content-Language", "Content-Type",
            "Expires", "X-Total-Count", "X-Total-Sum", "X-Total-Active"}, methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.OPTIONS})
    public ResponseData exception(BindException e) {
        log.warn("传入数据校验不通过:", e);
        BindingResult result = e.getBindingResult();
        ResponseData rs = new ResponseData();
        if (result.hasErrors()) {
            rs = new ResponseData(0, result.getAllErrors().get(0).getDefaultMessage());
        } else {
            rs.setStatus(0);
            rs.setMessage("未知数据校验不通过错误,请确认数据格式是否正确!");
        }
        return rs;
    }

    @ExceptionHandler(Throwable.class)
    @CrossOrigin(allowedHeaders = "*", origins = "*", allowCredentials = "false", exposedHeaders = {"Cache-Control", "Content-Language", "Content-Type",
            "Expires", "X-Total-Count", "X-Total-Sum", "X-Total-Active"}, methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.OPTIONS})
    public ResponseData exception(Throwable e) {
        log.error("Throwable:", e);
        return new ResponseData(0, "平台接口Exception异常,请联系客服处理!");
    }

    @ExceptionHandler(value = EmptyResultDataAccessException.class)
    @CrossOrigin(allowedHeaders = "*", origins = "*", allowCredentials = "false", exposedHeaders = {"Cache-Control", "Content-Language", "Content-Type",
            "Expires", "X-Total-Count", "X-Total-Sum", "X-Total-Active"}, methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.OPTIONS})
    public ResponseData EmptyResultDataAccessException(EmptyResultDataAccessException e) {
        log.warn("EmptyResultDataAccessException:", e);
        return new ResponseData(0, "该数据不存在，请核实后操作！");
    }


}
